package com.ssu.sslab;
import java.net.*;
import java.util.*;
import java.io.*;


import com.ssu.sslab.typeConvertor.*;

public class ClientSocketThread extends Thread implements ClientSensorInfoSetting{
	
	private Socket socket = null;
	private DataInputStream dis = null;
	private DataOutputStream dos = null;
	private int sequenceNum = -1;
	private ClientController cc;
	private int requestType;
	private int sensorID;
	
	//SocketProcess initialization 
	public ClientSocketThread(Socket socket,ClientController cc) throws Exception {
		this.socket = socket;
		this.cc = cc;
		new TypeConvertor();
		dis = new DataInputStream(socket.getInputStream());
		dos = new DataOutputStream(socket.getOutputStream());
	}
	
	/*************************************
	 * |ACK |
	 * ----------------------------------
	 * 
	 * 
	 * *********************************
	 * Protocol  generated
	 */
	public void ProtocalInfo(byte [] protocolData) {
	
		//[sequence number] setting,[total 4 bytes],byte[1]---byte[4]
		sequenceNum = sequenceNum + 1;
		protocolData[1] = (byte)(sequenceNum & 0xff);
		protocolData[2] = (byte)((sequenceNum >> 8) & 0xff);
		protocolData[3] = (byte)((sequenceNum >> 16) & 0xff);
		protocolData[4] = (byte)((sequenceNum >> 24) & 0xff);
		
		//[date] setting,YYYY--MM--DD,H--M--S,[total 7 bytes],byte[5]--byte[11]
		Calendar calendar = Calendar.getInstance();
		
		short year = (short)calendar.get(Calendar.YEAR);// YEAR: protocolData[5]-protocalData[6]
		protocolData[5] = (byte)(year & 0xff);
		protocolData[6] = (byte)((year>>8) & 0xff);
		
		protocolData[7] = (byte)(calendar.get(Calendar.MONTH)+1);//MONDAY: 
		protocolData[8] = (byte)(calendar.get(Calendar.DATE));//DATE: 
		protocolData[9] = (byte)calendar.get(Calendar.HOUR_OF_DAY);//HOUR:
		protocolData[10] = (byte)calendar.get(Calendar.MINUTE);//MINUTE:
		protocolData[11] = (byte)calendar.get(Calendar.SECOND);//SECOND:
		
		//[Device ID] setting,[total 4 bytes],byte[12]--byte[15]
		int deviceID = 12345;
		protocolData[12] = (byte)(deviceID & 0xff);
		protocolData[13] = (byte)((deviceID >> 8) & 0xff);
		protocolData[14] = (byte)((deviceID >> 16) & 0xff);
		protocolData[15] = (byte)((deviceID >> 24) & 0xff);
		
		//[SensorsNUM] setting,[total 1 byte],byte[16]
		int sensorNum = 3;
		protocolData[16] = (byte) sensorNum;
		
		//[Sensor ID] setting,[total: sensorNum byte],every sensor id use 1 byte.
		for (int i = 0; i < sensorNum; i++) {
			protocolData[17+i] = (byte)(i+1);
		}
		
		//[Sensor type] setting,[total: sensorNum byte],every sensor type use 1 byte.
		// int, string,float, boolean.1-2-3-4
		protocolData[16+sensorNum+1] = 1;
		protocolData[16+sensorNum+2] = 2;
		protocolData[16+sensorNum+3] = 1;
		
		//[Sensor value] setting,[]
		protocolData[16+sensorNum*2+1] = 23;
		protocolData[16+sensorNum*2+2] = 122;
		protocolData[16+sensorNum*2+3] = 111;
	}
	
	
	public void run() {
		byte [] sendBuf = new byte[512];
		byte [] receiveBuf = new byte[512];
		int cnt;
		
		
		
		while( true ) {
			requestType = cc.getRequestType();
			sensorID = cc.getSensorID();
			System.out.println("-------");
			
			try {
//				sendBuf[0] = 2; 
//				dos.write(sendBuf);
//				dos.flush();
				cnt = dis.read(receiveBuf);				
					
					switch (requestType) {
					case 0:
						sendBuf = AliveCheck();//Client send ACK = 0,SYN =1;
						if (cnt!= 0) {
							if(receiveBuf[0] == 6)//ACK = 1.SYN = 1;Alive Check!
							{
								System.out.println("Alive Check: Success");
							}
						}
						dos.write(sendBuf);
						dos.flush();
						break;
					case 1:
						sendBuf = setRequest(sensorID);//ACK =1,SYN =0
						dos.write(sendBuf);
						dos.flush();
						break;
					case 2:
						sendBuf = setRequestAll();//ACK =1,SYN =0
						dos.write(sendBuf);
						dos.flush();
						break;
					case 3:
						sendBuf = ConcelRequest(sensorID);//ACK =1,SYN =0
						dos.write(sendBuf);
						dos.flush();
						break;
					case 4:
						sendBuf = ConcelRequestAll();//ACK =1,SYN =0
						dos.write(sendBuf);
						dos.flush();
						break;
					default:
						break;
					}
//				Thread.sleep(1000);
				} catch (Exception e) {				
				e.printStackTrace();
			}
		}
	}
	
	
	/**
	 * 4 bytes array to int.
	 * @param bb
	 * @param index. begin to convert.
	 * @return 
	 */
	public int getInt(byte[] bb,int index){
		return (int) ((((bb[index + 3] & 0xff) << 24) | ((bb[index + 2] & 0xff) << 16) | ((bb[index + 1] & 0xff) << 8) | ((bb[index + 0] & 0xff) << 0)));
	}
	
	
	/**
	 * 2 bytes array to short
	 * @param b
	 * @param index
	 * @return
	 */
	public short getShort(byte[] b,int index){
		return (short)(((b[index+1] << 8) | b[index + 0] & 0xff));
	}
	
	
	
	//===================================================
	/****************************************************
	 *         Protocol header and data 
	 * -------------------------------------------------
	 * 	0                  7                  15
	 * --------------------------------------------------
	 *	|5 bits|ACK SYN FIN |      CheckAll    |  
	 * -------------------------------------------4 bytes
	 * 	| 4 bits|RequestType|      Check sum   |
	 * --------------------------------------------------
	 * |    data   38 bytes  .........          
	 * --------------------------------------------------
	 * 
	 * @author chengqiang sun
	 * 
	 ****************************************************/
	public byte[] AliveCheck(){
		byte[] request = new byte[512];
		request[0] = (byte)2;
		request[2] = (byte)0;
		return request;
	}
	public byte[] setRequest(int id){
		byte[] request = new byte[512];
		request[0] = (byte)4; //ACK = 1,SYN = 0,FIN = 0
		request[1] = (byte)0; //CheckAll = 0
		request[2] = (byte)1; // request by id 1
		request[3] = (byte)0;
		TypeConvertor.SetValueToByteArray(request, 4, id);
		
		return request;
	}
	
	public byte[] setRequestAll(){
		byte[] request = new byte[512];
		request[0] = (byte)4;//ACK = 1,SYN = 0,FIN = 0
		request[1] = (byte)1;
		request[2] = (byte)2;
		request[3] = (byte)0;
		
		return request;
		
	}
	
	public byte[] ConcelRequest(int id){
		byte[] request = new byte[512];
		request[0] = (byte)5;//ACK = 1,SYN = 0,FIN = 1
		request[1] = (byte)0;
		request[2] = (byte)3;
		request[3] = (byte)0;
		TypeConvertor.SetValueToByteArray(request, 4, id);
		
		return request;
	}
	
	public byte[] ConcelRequestAll() {
		byte[] request = new byte [512];
		request[0] = (byte)5;//ACK = 1,SYN = 0,FIN = 1
		request[1] = (byte)1;
		request[3] = (byte)4;
		request[4] = (byte)0;
		
		return request;
	}

	@Override
	public void PrintSensorInfo(byte[] receive) {
		// TODO Auto-generated method stub
		int sequenceID = TypeConvertor.SetByteArrayToInt(receive, 4); // sequenceId 4 bytes
		int sensorID = TypeConvertor.SetByteArrayToInt(receive, 8); // sensorID 4bytes
		String sensorName = "";
		sensorName = TypeConvertor.SetByteArrayToString(receive, 12, 8);
		
		String valueType = "";
		String descrip = "";
		String SensorIp = "";
		String date = "";
		switch (receive[20]) {
		case 0:
			valueType = "INT";
			int value = TypeConvertor.SetByteArrayToInt(receive, 21);
			descrip = TypeConvertor.SetByteArrayToString(receive, 25, 10);
			SensorIp = String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 35))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 37))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 39))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 41));
			date = String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 43))+"/"+ String.valueOf((int)receive[45])+"/"+String.valueOf((int)receive[46])+"."+String.valueOf((int)receive[47])+":"+String.valueOf((int)receive[48])+":"+String.valueOf((int)receive[49]);
			System.out.println(sequenceID+"  "+sensorID+"  "+sensorName+"  "+valueType+"  "+value+"  "+descrip+"  "+SensorIp+"  "+date);
			break;
		case 1:
			valueType = "SHORT";
			short valueShort = TypeConvertor.SetByteArrayToShort(receive, 21);
			descrip = TypeConvertor.SetByteArrayToString(receive, 23, 10);
			SensorIp = String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 33))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 35))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 37))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 39));
			date = String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 41))+"/"+ String.valueOf((int)receive[43])+"/"+String.valueOf((int)receive[44])+"."+String.valueOf((int)receive[45])+":"+String.valueOf((int)receive[46])+":"+String.valueOf((int)receive[47]);
			System.out.println(sequenceID+"  "+sensorID+"  "+sensorName+"  "+valueType+"  "+valueShort+"  "+descrip+"  "+SensorIp+"  "+date);
			break;
		case 2:
			valueType = "LONG";
			long valueLong = TypeConvertor.SetByteArrayToLong(receive, 21);
			descrip = TypeConvertor.SetByteArrayToString(receive, 29, 10);
			SensorIp = String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 39))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 41))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 43))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 45));
			date = String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 47))+"/"+ String.valueOf((int)receive[49])+"/"+String.valueOf((int)receive[50])+"."+String.valueOf((int)receive[51])+":"+String.valueOf((int)receive[52])+":"+String.valueOf((int)receive[53]);
			System.out.println(sequenceID+"  "+sensorID+"  "+sensorName+"  "+valueType+"  "+valueLong+"  "+descrip+"  "+SensorIp+"  "+date);
			
			break;
		case 3:
			valueType = "DOUBLE";
			double valueDouble = TypeConvertor.SetByteArrayToDouble(receive, 21);
			descrip = TypeConvertor.SetByteArrayToString(receive, 29, 10);
			SensorIp = String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 39))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 41))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 43))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 45));
			date = String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 47))+"/"+ String.valueOf((int)receive[49])+"/"+String.valueOf((int)receive[50])+"."+String.valueOf((int)receive[51])+":"+String.valueOf((int)receive[52])+":"+String.valueOf((int)receive[53]);
			System.out.println(sequenceID+"  "+sensorID+"  "+sensorName+"  "+valueType+"  "+valueDouble+"  "+descrip+"  "+SensorIp+"  "+date);
			
			break;
		case 4:
			valueType = "FLOAT";
			float valueFloat = TypeConvertor.SetByteArrayToFloat(receive, 21);
			descrip = TypeConvertor.SetByteArrayToString(receive, 25, 10);
			SensorIp = String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 35))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 37))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 39))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 41));
			date = String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 43))+"/"+ String.valueOf((int)receive[45])+"/"+String.valueOf((int)receive[46])+"."+String.valueOf((int)receive[47])+":"+String.valueOf((int)receive[48])+":"+String.valueOf((int)receive[49]);
			System.out.println(sequenceID+"  "+sensorID+"  "+sensorName+"  "+valueType+"  "+valueFloat+"  "+descrip+"  "+SensorIp+"  "+date);
			break;
		case 5:
			valueType = "BYTE";
			byte valueByte = TypeConvertor.SetByteArrayToByte(receive, 21);
			descrip = TypeConvertor.SetByteArrayToString(receive, 22, 10);
			SensorIp = String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 32))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 34))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 36))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 38));
			date = String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 40))+"/"+ String.valueOf((int)receive[42])+"/"+String.valueOf((int)receive[43])+"."+String.valueOf((int)receive[44])+":"+String.valueOf((int)receive[45])+":"+String.valueOf((int)receive[46]);
			System.out.println(sequenceID+"  "+sensorID+"  "+sensorName+"  "+valueType+"  "+valueByte+"  "+descrip+"  "+SensorIp+"  "+date);
			break;
		case 6:
			valueType = "STRING";
			int strLength = (int)receive[21];
			String valueString = new String(receive, 22, strLength);
			descrip = TypeConvertor.SetByteArrayToString(receive, 22+strLength, 10);
			SensorIp = String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 32+strLength))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 34+strLength))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 36+strLength))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 38+strLength));
			date = String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 40+strLength))+"/"+ String.valueOf((int)receive[42+strLength])+"/"+String.valueOf((int)receive[43+strLength])+"."+String.valueOf((int)receive[44+strLength])+":"+String.valueOf((int)receive[45+strLength])+":"+String.valueOf((int)receive[46+strLength]);
			System.out.println(sequenceID+"  "+sensorID+"  "+sensorName+"  "+valueType+"  "+valueString +"  "+descrip+"  "+SensorIp+"  "+date);
			break;
		case 7:
			valueType = "BOOLEAN";
			boolean valueBoolean = TypeConvertor.SetByteArrayToBoolean(receive, 21);
			descrip = TypeConvertor.SetByteArrayToString(receive, 22, 10);
			SensorIp = String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 32))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 34))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 36))+"."+String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 38));
			date = String.valueOf((int)TypeConvertor.SetByteArrayToShort(receive, 40))+"/"+ String.valueOf((int)receive[42])+"/"+String.valueOf((int)receive[43])+"."+String.valueOf((int)receive[44])+":"+String.valueOf((int)receive[45])+":"+String.valueOf((int)receive[46]);
			System.out.println(sequenceID+"  "+sensorID+"  "+sensorName+"  "+valueType+"  "+valueBoolean+"  "+descrip+"  "+SensorIp+"  "+date);
			break;
		}
		
		
	}

	@Override
	public String TypeConvertor(byte type) {
		// TODO Auto-generated method stub
		return null;
	}
	
	
	
	
}
